﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KalevaAalto
{
    public static partial class Static
    {



        #region AddLazy
        public static IServiceCollection AddLazy<T>(this IServiceCollection services, Func<T> func) where T : class
        {
            var lazy = new Lazy<T>(func);
            return services.AddTransient(it => lazy.Value);
        }

        public static IServiceCollection AddLazy<T>(this IServiceCollection services, Func<IServiceProvider, T> func) where T : class
        {
            return services.AddSingleton(it =>
            {
                return new Lazy<T>(() => func(it));
            }).AddTransient(it => it.GetService<Lazy<T>>()!.Value);
        }








        

        public static IServiceCollection AddAsyncLazy<T>(this IServiceCollection services, T value) where T : class
        {
            return services.AddSingleton(Task.FromResult(value));
        }

        public static IServiceCollection AddAsyncLazy<T>(this IServiceCollection services, Func<T> func) where T : class
        {
            var lazy = new Lazy<T>(func);
            return services.AddTransient(it=>Task.FromResult(lazy.Value));
        }

        public static IServiceCollection AddAsyncLazy<T>(this IServiceCollection services, Func<Task<T>> func) where T : class
        {
            var lazy = new Lazy<Task<T>>(func);
            return services.AddSingleton(lazy.Value);
        }


        public static IServiceCollection AddAsyncLazy<T>(this IServiceCollection services, Func<IServiceProvider, T> func) where T : class
        {
            return services.AddSingleton(it =>
            {
                return new Lazy<Task<T>>(async () => func(it));
            }).AddTransient(it => it.GetService<Lazy<Task<T>>>()!.Value);
        }

        public static IServiceCollection AddAsyncLazy<T>(this IServiceCollection services, Func<IServiceProvider, Task<T>> func) where T : class
        {
            return services.AddSingleton(it =>
            {
                return new Lazy<Task<T>>(async () => await func(it));
            }).AddTransient(it => it.GetService<Lazy<Task<T>>>()!.Value);
        }

        #endregion



        #region GetService

        public static T GetServiceUnCheck<T>(this IServiceProvider services)
        {
            var value = services.GetService<T>();
            return value!;
        }


        public static async Task<T?> GetServiceAsync<T>(this IServiceProvider services)
        {
            var task = services.GetService<Task<T>>();
            if (task is null)
            {
                return default(T);
            }
            return await task;
        }

        public static async Task<T> GetServiceUnCheckAsync<T>(this IServiceProvider services)
        {
            var value = await GetServiceAsync<T>(services);
            return value!;
        }

        #endregion
    }
}
